Skip to content

ci(release): derive release notes from CHANGELOG.md (single source of truth)#52

Merged
aksOps merged 1 commit intomainfrom
release-extract-changelog
Apr 23, 2026
Merged

ci(release): derive release notes from CHANGELOG.md (single source of truth)#52
aksOps merged 1 commit intomainfrom
release-extract-changelog

Conversation

@aksOps
Copy link
Copy Markdown
Contributor

@aksOps aksOps commented Apr 23, 2026

Summary

Wires CHANGELOG.md into the release workflow as the single source of truth for release notes. Replaces `--generate-notes` (raw PR list — disqualified by OpenSSF BestPractices `release_notes`) with curated content extracted from the CHANGELOG.

Contributor workflow

  1. As part of any PR worth mentioning in release notes, add a bullet under `## [Unreleased]` in `CHANGELOG.md`.
  2. When releasing:
    • Fire `release.yml` via `workflow_dispatch` with a bump (patch/minor/major).
    • The workflow auto-promotes `[Unreleased]` → `[X.Y.Z] — YYYY-MM-DD`, inserts a fresh `[Unreleased]` above it, commits the rename to main as `github-actions[bot]`.
    • The extracted section becomes the GitHub release body.
  3. If `[Unreleased]` is empty when you fire the workflow, the release fails with a clear instruction. No silent `--generate-notes` fallback — you curate or you don't release.

Implementation

New step: `Resolve release notes from CHANGELOG.md` (runs after `download-artifact`):

  • awk-extracts the block under `## []` up to the next `## [` heading.
  • Tries `## [vX.Y.Z]` then `## [X.Y.Z]` (the file convention is no-`v`; Keep-a-Changelog style).
  • If the tag's section is absent, promotes `[Unreleased]` via a tiny inline Python edit and pushes the rename commit to main.
  • Fails fast if neither the target section nor a non-empty `[Unreleased]` exists.
  • Emits the extracted section as a multi-line step output.

Modified step: `Create GitHub release` — now writes `release-notes.md` from the extracted body + the existing cosign Verify footer, and passes it via `--notes-file`. Removes the draft-then-edit dance.

CHANGELOG.md — adds a contributor note at the top explaining the promotion flow so it's discoverable without reading release.yml.

Consequences

  • ✅ `release_notes` BestPractices criterion stays Met across every future release — by construction.
  • ✅ CHANGELOG.md on main always reflects what was released.
  • ⚠️ The binary's embedded `Commit` SHA is the pre-rename commit (`github.sha` captured during the build job), while the tag points to the post-rename commit. The binary bytes are unaffected. Acceptable mismatch — CHANGELOG.md is doc, not code.

Test plan

🤖 Generated with Claude Code

Previously `release.yml` ran `gh release create --generate-notes`, which
produces GitHub's raw PR-list auto-summary. OpenSSF BestPractices
`release_notes` explicitly disqualifies that form — release notes must
be a human-readable curated summary of major changes and upgrade impact.

This ties the release workflow to CHANGELOG.md as the single source:

  1. After artifact download, a new "Resolve release notes" step:
     - Looks for `## [vX.Y.Z]` or `## [X.Y.Z]` in CHANGELOG.md.
     - If missing, promotes non-empty `## [Unreleased]` → `## [X.Y.Z] — <today>`,
       inserts a fresh `## [Unreleased]` above it, commits the rename to
       main as github-actions[bot], and re-extracts.
     - If neither [Unreleased] nor [X.Y.Z] have content, fails with a
       clear instruction to populate CHANGELOG.md.
     - Emits the extracted section as a multi-line step output.

  2. The "Create GitHub release" step consumes that output via
     `--notes-file` (prepended to the existing cosign Verify footer).
     The old draft-then-edit dance is gone.

CHANGELOG.md gets a short contributor note explaining the flow so the
promotion is discoverable.

One acceptable consequence: the binary's embedded Commit SHA refers to
the pre-rename commit (github.sha captured by the build job), while the
tag points to the post-rename commit. The binary bytes are unaffected;
only the CHANGELOG.md doc differs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@aksOps aksOps enabled auto-merge (squash) April 23, 2026 07:31
@aksOps aksOps merged commit 5981771 into main Apr 23, 2026
11 checks passed
@aksOps aksOps deleted the release-extract-changelog branch April 23, 2026 07:36
aksOps added a commit that referenced this pull request Apr 23, 2026
…ation at CHANGELOG.md (#53)

- README.md: add BestPractices badge (project 12628) next to the
  Security Scan + OpenSSF Score badges.
- .bestpractices.json: release_notes_justification now points at the
  curated CHANGELOG.md (the single source of truth after PR #51/#52),
  not the raw-PR-list GitHub releases page.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant